package com.cb.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cb.dto.AssignAuthDto;
import com.cb.entity.Auth;
import com.cb.entity.Role;
import com.cb.entity.RoleAuth;
import com.cb.mapper.AuthMapper;
import com.cb.service.AuthService;
import com.cb.service.RoleAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@CacheConfig(cacheNames = "com.cb.service.impl.AuthServiceImpl")
@Service
@Transactional
public class AuthServiceImpl extends ServiceImpl<AuthMapper, Auth> implements AuthService{

    @Autowired
    private AuthMapper authMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RoleAuthService roleAuthService;

    @Override
    public List<Auth> findAuthTree(int userId) {
        //先从redis中查询缓存,查到的是权限(菜单)树List<Auth>转的json串
        String authTreeJson = redisTemplate.opsForValue().get("authTree:" + userId);
        if(StringUtils.hasText(authTreeJson)){ //redis中查到缓存
            //将json串转回权限(菜单)树List<Auth>并返回
            return JSON.parseArray(authTreeJson, Auth.class);
        }
        //redis中没有查到缓存,从数据库表中查询所有权限(菜单)
        List<Auth> allAuth = authMapper.findAllAuth(userId);
        //将所有权限(菜单)List<Auth>转成权限(菜单)树List<Auth>
        List<Auth> authTreeList = allAuthToAuthTree(allAuth, 0);
        //将权限(菜单)树List<Auth>转成json串并保存到redis
        redisTemplate.opsForValue().set("authTree:"+userId,JSON.toJSONString(authTreeList));
        //返回权限(菜单)树List<Auth>
        return authTreeList;
    }

    @Cacheable(key = "'all:authTree'")
    @Override
    public List<Auth> allAuthTree() {
        //查询所有菜单树
        LambdaQueryWrapper<Auth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Auth::getAuthState,1);
        List<Auth> authList = baseMapper.selectList(queryWrapper);
        return allAuthToAuthTree(authList, 0);
    }

    //将所有权限(菜单)转成权限(菜单)树的递归算法
    private List<Auth> allAuthToAuthTree(List<Auth> allAuthList, int parentId){
        //获取父权限(菜单)id为参数parentId的所有权限(菜单)
        ArrayList<Auth> firstLevelAuthList = new ArrayList<>();
        for (Auth auth : allAuthList) {
            if(auth.getParentId()==(parentId)){
                firstLevelAuthList.add(auth);
            }
        }
        //查询firstLevelAuthList每个权限(菜单)的所有子级权限(菜单)
        for (Auth firstAuth : firstLevelAuthList) {
            List<Auth> secondLevelAuthList = allAuthToAuthTree(allAuthList, firstAuth.getAuthId());
            firstAuth.setChildAuth(secondLevelAuthList);
        }
        return firstLevelAuthList;
    }

    @Override
    public List<Auth> queryRoleAuth(Integer roleId) {
        List<Auth> auths=new ArrayList<>();
        List<RoleAuth> roleAuths=roleAuthService.getByUserId(roleId);
        if(roleAuths.size()==0){
            return auths;
        }
        ArrayList<Integer> integers = new ArrayList<>();
        for (RoleAuth auth : roleAuths) {
            integers.add(auth.getAuthId());
        }
        LambdaQueryWrapper<Auth> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(Auth::getAuthId,integers);
        auths=baseMapper.selectList(lambdaQueryWrapper);
        return auths;
    }

    @Override
    public void assignAuth(AssignAuthDto assignAuthDto) {
        //角色id
        Integer roleId = assignAuthDto.getRoleId();
        //给角色分配的所有权限(菜单)id
        List<Integer> authIds = assignAuthDto.getAuthIds();
        //根据角色id删除给角色已分配的所有权限(菜单)
        int result = roleAuthService.delAuthByRoleId(roleId);
        //添加角色权限(菜单)关系
        for (Integer authId : authIds) {
            RoleAuth roleAuth = new RoleAuth();
            roleAuth.setRoleId(roleId);
            roleAuth.setAuthId(authId);
            roleAuthService.save(roleAuth);
        }
    }
}
